package cn.sc.summer.redis.redisson;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.sc.summer.redis.redisson.enums.RedisConnectionTypeEnum;
import cn.sc.summer.redis.redisson.property.RedissonProperties;
import cn.sc.summer.redis.redisson.strategy.RedissonConfigService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.config.Config;

import java.util.Optional;

/**
 * @author a-xin
 * @Description: Redisson核心配置，用于提供初始化的redisson实例
 * @date 2019/6/19 下午10:16
 */
@Slf4j
public class RedissonManager {

    private final Redisson redisson;

    public RedissonManager(RedissonProperties redissonProperties) {
        try {
            //通过不同部署方式获得不同config实体
            Config config = RedissonConfigFactory.getInstance().createConfig(redissonProperties);
            redisson = (Redisson) Redisson.create(config);
        } catch (Exception e) {
            log.error("Redisson init error : ", e);
            throw new IllegalArgumentException("Please input correct configurations, connectionType must in standalone/sentinel/cluster/masterSlave");
        }
    }

    public Redisson getRedisson() {
        return redisson;
    }

    /**
     * Redisson连接方式配置工厂
     * 双重检查锁
     */
    static class RedissonConfigFactory {

        private RedissonConfigFactory() {
        }

        private static volatile RedissonConfigFactory factory = null;

        public static RedissonConfigFactory getInstance() {
            if (factory == null) {
                synchronized (Object.class) {
                    if (factory == null) {
                        factory = new RedissonConfigFactory();
                    }
                }
            }
            return factory;
        }

        /**
         * 根据连接类型获取对应连接方式的配置,基于策略模式
         *
         * @param redissonProperties redis连接信息
         * @return Config
         */
        public Config createConfig(RedissonProperties redissonProperties) {

            if (ObjectUtil.isNull(redissonProperties)) {
                throw new RuntimeException("redisson config can not be NULL!");
            }
            if (StrUtil.isBlank(redissonProperties.getHost())) {
                throw new RuntimeException("redisson.lock.server.address cannot be NULL!");
            }
            if (StrUtil.isBlank(redissonProperties.getType())) {
                throw new RuntimeException("redisson.lock.server.password cannot be NULL!");
            }

            String connectionType = redissonProperties.getType();
            RedisConnectionTypeEnum redisConnectionTypeEnum = Optional.ofNullable(RedisConnectionTypeEnum.getByType(connectionType))
                    .orElseThrow(() -> new IllegalArgumentException("==> Creating a Redisson connection to Config failed! The current connection method: " + connectionType));
            RedissonConfigService redissonConfigService = SpringUtil.getBean(redisConnectionTypeEnum.getClazz());
            return redissonConfigService.createRedissonConfig(redissonProperties);
        }
    }

}


